// MdSpi.cpp: implementation of the CMdSpi class.
//
//////////////////////////////////////////////////////////////////////

#include "MdSpi.h"
#include <sys/types.h>
#include <sys/stat.h>

IFutureMD* CreateMD(const char *pszConfigFile){
	CMdSpi2* pMdSpi = new CMdSpi2(pszConfigFile);
	pMdSpi->InitMyConfig(pszConfigFile);

	CCtpFutureMD* pMd = new CCtpFutureMD();
	pMd->m_pSpi = pMdSpi;
	pMdSpi->m_pMd = pMd;

	return pMd;
}

void * CheckThreadProc(void *lParam){
	/*CMdSpi2* pSpi = (CMdSpi2*)lParam;
	while(true){
		pthread_testcancel();
		sleep(1);
		pSpi->Check();
	}
	pthread_detach(pthread_self());*/
	return 0;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMdSpi2::CMdSpi2() //todo:m_Config(pszInitFile)
{
	m_cIniFile[0]='\0';
	m_bOnline = false;
	m_pMdApi = NULL;
	m_pAllMarketData3 = NULL;
	m_pConfig3 = NULL;

	//pthread_create(&m_pthread,NULL,CheckThreadProc,(void *)this);
}

CMdSpi2::CMdSpi2(const char *pszInitFile) //todo:m_Config(pszInitFile)
{
	strcpy(m_cIniFile,pszInitFile);
	m_bOnline = false;
	m_pMdApi = NULL;
	m_pAllMarketData3 = NULL;
	m_pConfig3 = NULL;
	//pthread_create(&m_pthread,NULL,CheckThreadProc,(void *)this);
}

CMdSpi2::~CMdSpi2()
{
	pthread_cancel(m_pthread);
	sleep(2);

	if(m_pMdApi!=NULL){
		m_pMdApi->RegisterSpi(NULL);
		m_pMdApi->Release();
	}
	delete m_pAllMarketData3;
	delete m_pConfig3;
}

void CMdSpi2::OnFrontConnected(){
	printf("login md ...\n");
	CThostFtdcReqUserLoginField reqUserLogin;
	memset(&reqUserLogin,0,sizeof(reqUserLogin));

	strcpy(reqUserLogin.BrokerID, m_pConfig3->GetBroker());
	strcpy(reqUserLogin.UserID, m_pConfig3->GetUser());
	strcpy(reqUserLogin.Password, m_pConfig3->GetPassword());

	//send login request;
	m_pMdApi->ReqUserLogin(&reqUserLogin, 0);
}

void CMdSpi2::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
	if(pRspInfo && pRspInfo->ErrorID==0){

		m_SubLock.Lock();
		m_bOnline = true;
		//m_pMdApi->SubscribeMarketDataTopic(100,USTP_TERT_QUICK);
		//m_pMdApi->SubscribeMarketDataTopic(21001,USTP_TERT_QUICK);

		if(!m_SubScribeCount.empty()){
			char **ppCodes = new char*[m_SubScribeCount.size()];
			int count=0;
			map<string,int>::iterator it = m_SubScribeCount.begin();
			map<string,int>::iterator end = m_SubScribeCount.end();
			while(it != end){
				const char * code = it->first.c_str();
				ppCodes[count] = new char[strlen(code)+1];
				strcpy(ppCodes[count],code);
				count++;
				it++;
			}
			m_pMdApi->SubscribeMarketData(ppCodes,count);

			for(int i=0;i<count;i++){
				delete[] ppCodes[i];
			}

			delete[] ppCodes;
		}
		m_SubLock.Unlock();
		m_nLastError =0;
		m_cLastError[0]='\0';

		printf("md logined\n");
	}else if(pRspInfo){
		m_nLastError = pRspInfo->ErrorID;
		strcpy(m_cLastError,pRspInfo->ErrorMsg);

		printf("failed to login md:%d,%s\n",pRspInfo->ErrorID,pRspInfo->ErrorMsg);
	}

	m_hEvent.fire();
};

void CMdSpi2::OnFrontDisconnected(int nReason){

};

void CMdSpi2::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData) {
	MarketDataField* pData = m_pAllMarketData3->AddMarketDataField(pDepthMarketData);
	if(pData != NULL){
		m_ListenerLock.Lock();
		list<IMarketDataListener*>::iterator it = m_Listeners.begin();
		list<IMarketDataListener*>::iterator end = m_Listeners.end();
		while(it != end){
			IMarketDataListener* pListener = *it;
			pListener->OnFutureMarketData(pData);
			it++;
		}
		m_ListenerLock.Unlock();
	}
}

int CMdSpi2::SubscribeMarketData(const char * code){
	int index =0;
	char **pNewCodes = new char*[1];
	int nRet =0;

	m_SubLock.Lock();
	map<string,int>::iterator it = m_SubScribeCount.find(code);
	if(it == m_SubScribeCount.end()){
		m_SubScribeCount.insert(pair<string,int>(code,1));	
		pNewCodes[index++]=new char[32];
		strcpy(pNewCodes[0],code);
	}else{
		it->second = it->second+1;
	}
	
	if(index >0){
		if(m_bOnline){
			nRet = m_pMdApi->SubscribeMarketData(pNewCodes,index);
			if(nRet != 0){
				printf("subscribe md return non-zero: %s, errorid:%d\n",pNewCodes[0],nRet);
			}
		}
		delete[] pNewCodes[0];
	}

	delete[] pNewCodes;

	m_SubLock.Unlock();

	printf("sub md: %s\n",code);

	return nRet;
}

//unscribe market data;
void CMdSpi2::UnsubscribeMarketData(const char * code){
	int index =0;
	char **pNewCodes = new char*[1];

	m_SubLock.Lock();
	map<string,int>::iterator it = m_SubScribeCount.find(code);
	if(it != m_SubScribeCount.end()){
		it->second = it->second-1;
		if(it->second<=0){
			m_SubScribeCount.erase(code);	
			pNewCodes[index++]=new char[32];
			strcpy(pNewCodes[0],code);
		}
	}


	if(index >0){
		if(m_bOnline){
			m_pMdApi->UnSubscribeMarketData(pNewCodes,index);
		}
		delete[] pNewCodes[0];
	}

	delete[] pNewCodes;

	m_SubLock.Unlock();
}

void CMdSpi2::InitMyConfig(const char *pszInit){
	strcpy(m_cIniFile,pszInit);
	m_pConfig3 = new CMyConfig2();
	m_pConfig3->LoadConfig(pszInit);
	m_pAllMarketData3 = new CAllMarketData();
}

int CMdSpi2::Login(const char* UserID,const char* Password,char* ErrorMsg,int* ErrorID){
	int nCode = Login(UserID,Password);
	*ErrorID = nCode;
	strcpy(ErrorMsg,m_cLastError);
	return nCode;
}

int CMdSpi2::Login(const char *pszUserID,const char *pszPassword){
	char cDir[64];
	char cServer[128];
	
	mkdir("./tmp",0755);
	strcpy(cDir,"./tmp/");
	strcat(cDir,pszUserID);
	strcat(cDir,"_md");
	mkdir(cDir,0755);
	strcat(cDir,"/");

	m_pConfig3->SetUser(pszUserID);
	m_pConfig3->SetPassword(pszPassword);

	m_pMdApi = CThostFtdcMdApi::CreateFtdcMdApi(cDir);
	
	m_pMdApi->RegisterSpi(this);

	list<string>* pList = m_pConfig3->m_MDServers["default"];
	if(pList != NULL){
		list<string>::iterator it = pList->begin();
		list<string>::iterator end = pList->end();
		while(it != end){
			strcpy(cServer,it->c_str());
			m_pMdApi->RegisterFront(cServer);

			it++;
		}
	}

	m_pMdApi->Init();

	m_hEvent.wait();

	return 0;
}

void CMdSpi2::AddListener(IMarketDataListener*  pListener){
	m_ListenerLock.Lock();
	m_Listeners.push_back(pListener);
	//pListener->OnSetFutureMD((IFutureMD*)m_pMd);
	m_ListenerLock.Unlock();
}

void CMdSpi2::RemoveListener(IMarketDataListener*  pListener){
	m_ListenerLock.Lock();
	m_Listeners.remove(pListener);
	m_ListenerLock.Unlock();
}

void CMdSpi2::Stop(){
	if(m_pMdApi!=NULL){
		m_pMdApi->RegisterSpi(NULL);
		m_pMdApi->Release();
		m_pMdApi = NULL;
	}
}

void CMdSpi2::Release(){
	delete this;
}


/**
 *login to trade;
 */
int		CCtpFutureMD::Login(const char* UserID,const char* Password,char* ErrorMsg,int* ErrorID){
	return m_pSpi->Login(UserID,Password,ErrorMsg,ErrorID);
}

int	CCtpFutureMD::SubscribeMarketData(const char *InstrumentID){
	return m_pSpi->SubscribeMarketData(InstrumentID);
}

void	CCtpFutureMD::UnsubscribeMarketData(const char *InstrumentID){
	m_pSpi->UnsubscribeMarketData(InstrumentID);
}

void	CCtpFutureMD::AddListener(IMarketDataListener* pListener){
	m_pSpi->AddListener(pListener);
}

void	CCtpFutureMD::RemoveListener(IMarketDataListener* pListener){
	m_pSpi->RemoveListener(pListener);
}

void CCtpFutureMD::Stop(){
	m_pSpi->Stop();
}

void	CCtpFutureMD::Release(){
	m_pSpi->Release();
	delete this;
}
